package com.inspinia.auth.rpc.service;

import cn.hutool.core.collection.CollectionUtil;
import com.inspinia.auth.dao.AuthDao;
import com.inspinia.auth.rpc.api.AuthService;
import com.inspinia.auth.rpc.config.RoleConfig;
import com.inspinia.upms.common.model.resource.UpmsResource;
import com.inspinia.upms.common.model.role.UpmsRole;
import com.inspinia.upms.common.model.user.UpmsUser;
import com.inspinia.upms.common.model.user.UpmsUserStatus;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Veblen
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Resource
    private AuthDao authDao;

    @Override
    public UpmsUser findUser(String username, String pwd) {
        return authDao.findUser(username,pwd);
    }

    @Override
    public SimpleAuthorizationInfo getAuthorizationInfo(String userName,String appName) {
        UpmsUser user = authDao.findByUserName(userName);

        if (user != null) {
            long userId = user.getUserId();

            //首先判断用户是否已被禁用。
            int status = authDao.getUserStatus(userId);
            if (status == UpmsUserStatus.DISABLE.getCode()) {
                return null;
            }

            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            List<Long> roleIds = authDao.findRoleIdsByUser(userId);
            if (roleIds == null && !roleIds.isEmpty()) {
                throw new RuntimeException("登录超时,或您没有权限访问该页面");
            }
            List<UpmsRole> roles = authDao.findRolesById(roleIds);
            user.setRoles(roles);
            Set<String> resourceUrls = new HashSet<>();
            for (UpmsRole role : roles) {
                info.addRole(role.getRoleName());
                //如果是超级管理员并且没有
                if (RoleConfig.superUser.equals(role.getRoleName())){
                    //超级管理员用户放行
                    resourceUrls.add("*");
                }else{
                    // 获取用户所拥有的功能集合
                    List<String> resource = authDao.findResourcesByRole(role.getId(), appName);
                    resourceUrls.addAll(resource);
                }
            }

            //获取用户的岗位拥有功能集合
            List<Long> postIds = authDao.findPostIdsByIdUser(userId);
            if (CollectionUtil.isNotEmpty(postIds)) {
                List<String> urlsByPostIds = authDao.findResourceUrlsByPostIds(postIds, appName);
                resourceUrls.addAll(urlsByPostIds);
            }

            // 设置用户所拥有的功能集合
            Iterator<String> iterator = resourceUrls.iterator();
            String windowLine = "\r\n";
            String linuxLine = "\n";
            while (iterator.hasNext()) {
                String url = iterator.next();
                if (url != null && url != "") {
                    //解决根据\n分隔之后,某些url带有 /per/xxx\r的情况。
                    String[] urls;
                    if (url.indexOf(windowLine) != -1) {
                        urls = url.split(windowLine);
                    } else {
                        urls = url.split(linuxLine);
                    }
                    info.addStringPermissions(Arrays.asList(urls));
                }
            }
            return info;

        }
        return null;
    }

    @Override
    public List<UpmsResource> findResourcesByUser(Long userId) {
        List<Long> roleIds = authDao.findRoleIdsByUser(userId);
        List<UpmsRole> roleByRoleIds = findRoleByRoleIds(roleIds);
        boolean isSuper = hasRole(RoleConfig.superUser,roleByRoleIds);

        List<UpmsResource> resources;
        if (isSuper) {
            resources = authDao.findAllMenu();
        } else {
            resources = authDao.findMenusByRole(roleIds);
        }

        if (CollectionUtil.isNotEmpty(resources)){
           return hasChildResource(resources);
        }
        return new ArrayList<>();
    }

    @Override
    public UpmsUser getUserByPrincipal(PrincipalCollection principals) {
        UpmsUser shiroUser = null;
        if (Objects.nonNull(principals)){
            if (principals.getPrimaryPrincipal() instanceof UpmsUser){
                shiroUser = (UpmsUser) principals.getPrimaryPrincipal();
            }else{
                shiroUser = authDao.findById(Long.valueOf((String)principals.getPrimaryPrincipal()));
            }
        }
        return shiroUser;
    }

    /**
     * 节点是否有子节点
     * @param resources
     */
    private List<UpmsResource> hasChildResource(List<UpmsResource> resources){
        //判断是否有子节点
        for (UpmsResource resource: resources) {
            List<UpmsResource> collect = resources.stream().filter(itme -> {
                return Objects.nonNull(itme.getPid()) && itme.getPid().equals(resource.getId());
            }).collect(Collectors.toList());

            if (collect.size() > 0){
                resource.setHasChildren(true);
            }
        }
        return resources;
    }

    /**
     * 判断用户是否有某个角色
     * @return
     */
    private boolean hasRole(String roleName,List<UpmsRole> roles){
        if (CollectionUtil.isEmpty(roles)){
            return false;
        }
        return roles.stream().allMatch(item -> item.getRoleName().equals(roleName));
    }

    /**
     * 根据roleId获取所有角色
     * @param roleIds
     * @return
     */
    private List<UpmsRole> findRoleByRoleIds(List<Long> roleIds) {
        if (CollectionUtil.isNotEmpty(roleIds)){
            return authDao.findRolesById(roleIds);
        }
        return new ArrayList<>();
    }

    /**
     * 查找所有级别的子菜单
     *
     * @param rootId 根菜单id
     * @param list   装入菜单的list
     * @return 所有的子菜单
     */
    private List<UpmsResource> findChildrenMenu(Long rootId, List<UpmsResource> list) {
        List<UpmsResource> resources = authDao.findChildrenMenu(rootId);
        if (null != resources && !resources.isEmpty()) {
            list.addAll(resources);
            for (UpmsResource child : resources) {
                findChildrenMenu(child.getId(), list);
            }
        }
        return list;
    }

    @Override
    public UpmsUser findById(Long userId) {
        return authDao.findById(userId);
    }

    @Override
    public UpmsUser findByUserName(String userName) {
        return authDao.findByUserName(userName);
    }
}
